﻿using System;
using Demo.Framework.GameObjects;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Demo.Framework.Camera
{
    public class FreeCamera : BaseCamera
    {
        //TPS Camera
        public Vector3 Target { get; set; }
        public Vector3 FollowTargetPosition { get; set; }
        public Vector3 FollowTargetRotation { get; set; }
        public Vector3 PositionOffset { get; set; }
        public Vector3 TargetOffset { get; set; }
        public Vector3 RelativeCameraRotation { get; set; }
        private float _springinnes = 0.15f;

        public float Springinnes
        {
            get { return _springinnes; }
            set { _springinnes = MathHelper.Clamp(value, 0, 1); }
        }

        public Vector3 PlayerPosition { get; set; }


        // Free Camera
        private float _leftrightRot;
        private float _updownRot;

        public Vector3 _target;
        private Vector3 _up;

        private readonly int _width;
        private readonly int _height;
       
        private bool _mouseControl;
        private MouseState _originalMouseState;
        private MouseState _currentMouseState;

        private float _rotationSpeed = 0.005f;
        private float _sensibility = 0.5f;
        private float _moveSpeed = 20f;
        private float _topY = 1.3f;
        private float _bottomY = -0.9f;
        public Matrix YRotation { get; set; }
    

        public Vector3 Position { get; set; }

        public bool MouseControl
        {
            get { return _mouseControl; } 
            set { _mouseControl = value; }
        }

        public float RotationSpeed
        {
            get { return _rotationSpeed; }
            set { _rotationSpeed = value; }
        }

        public float Sensibility
        {
            get { return _sensibility; }
            set { _sensibility = value; }
        }

        public float MoveSpeed
        {
            get { return _moveSpeed; }
            set { _moveSpeed = value; }
        }


        public FreeCamera(Viewport viewport, Vector3 position, Vector3 up, GraphicsDevice graphicsDevice, float updownAngle = 0, float leftrightAngle = 0)
            : base(graphicsDevice)
        {
            Position = position;

            _leftrightRot = leftrightAngle;
            _updownRot = updownAngle;
            _up = up;
            _width = viewport.Width;
            _height = viewport.Height;          

            Mouse.SetPosition(viewport.Width / 2, viewport.Height / 2);
            _originalMouseState = Mouse.GetState();

            UpdateViewMatrix();

            _mouseControl = true;
            //Player player = new Player(new BasicModel(, graphicsDevice);
        }

        public override void Update(GameTime gameTime)
        {
            if (_mouseControl)
            {
                _currentMouseState = Mouse.GetState();

                if (_currentMouseState != _originalMouseState)
                {
                    float xDifference = _currentMouseState.X - _originalMouseState.X;
                    float yDifference = _currentMouseState.Y - _originalMouseState.Y;
                    _leftrightRot -= _rotationSpeed * xDifference;
                    _updownRot -= _rotationSpeed * yDifference;
                    if (_updownRot>=_topY)
                    {
                        _updownRot = _topY;
                    }
                    else if (_updownRot<=_bottomY)
                    {
                        _updownRot = _bottomY;
                    }   
                    Mouse.SetPosition(_width / 2, _height / 2);
                    UpdateViewMatrix();
                    _currentMouseState = _originalMouseState;
                }
            }

            KeyboardState keyState = Keyboard.GetState();

            if (keyState.IsKeyDown(Keys.Up) || keyState.IsKeyDown(Keys.W))
            {
                AddToCameraPosition(new Vector3(0, 0, -_sensibility));

            }
            if (keyState.IsKeyDown(Keys.Down) || keyState.IsKeyDown(Keys.S))
            {
                AddToCameraPosition(new Vector3(0, 0, _sensibility));

            }
            if (keyState.IsKeyDown(Keys.Right) || keyState.IsKeyDown(Keys.D))
            {
                AddToCameraPosition(new Vector3(_sensibility, 0, 0));

            }
            if (keyState.IsKeyDown(Keys.Left) || keyState.IsKeyDown(Keys.A))
            {
                AddToCameraPosition(new Vector3(-_sensibility, 0, 0));

            }
            if (keyState.IsKeyDown(Keys.Space))
            {
                AddToCameraPosition(new Vector3(0, _sensibility, 0));

            }
            if (keyState.IsKeyDown(Keys.LeftControl))
            {
                AddToCameraPosition(new Vector3(0, -_sensibility, 0));

            }
        }

        //public void GetCurrentCamera()
        //{
        //    KeyboardState keyboardState = Keyboard.GetState();
        //    if (keyboardState.IsKeyDown(Keys.Tab))
        //    {
        //        _cameraStateKeyDown = true;
        //    }
        //    else if (_cameraStateKeyDown)
        //    {
        //        _cameraStateKeyDown = false;
        //        CameraState += 1;
        //        CameraState %= 3;
        //    }

        //}

        private void UpdateViewMatrix()
        {
            YRotation = Matrix.CreateRotationY(_leftrightRot);
            
            Matrix cameraRotation = Matrix.CreateRotationX(_updownRot) * Matrix.CreateRotationY(_leftrightRot);
            Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
            Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
            Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
            _target = Position + cameraRotatedTarget;
            _up = Vector3.Transform(cameraOriginalUpVector, cameraRotation);
            View = Matrix.CreateLookAt(Position, _target, _up);
        }

        private void AddToCameraPosition(Vector3 vectorToAdd)
        {
            Console.WriteLine(" UP Down is " + _updownRot);
            Matrix cameraRotation = Matrix.CreateRotationX(_updownRot) * Matrix.CreateRotationY(_leftrightRot);
            Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
            Position += _moveSpeed * rotatedVector;
            UpdateViewMatrix();
        }

        
    }
}

